#include "Managers/CraftingRecipesManager.h"
#include "Utils/Utils.h"
#include "Terrain/Terrain.h"

namespace PocketSurvival
{
    CraftingRecipesManager::CraftingRecipesManager() {}
    CraftingRecipesManager::~CraftingRecipesManager() {}

    void CraftingRecipesManager::loadGame()
    {
        std::string craftingRecipesJsonText;
        if(Utils::LoadTextFile("./content/recipe/CraftingRecipe.json", craftingRecipesJsonText) == true)
        {
            loadCraftingRecipeSource(nlohmann::json::parse(craftingRecipesJsonText));
        }
    }

    void CraftingRecipesManager::loadCraftingRecipeSource(const nlohmann::json &jsonData)
    {
        for(const auto &jsonKv : jsonData.items())
        {
            for(const nlohmann::json &recipeJson : jsonKv.value())
            {
                CraftingRecipe *recipe = new CraftingRecipe;
                memset(recipe->ingredients, 0, sizeof(recipe->ingredients));
                memset(recipe->ingredientsDataBit, 0xFF, sizeof(recipe->ingredientsDataBit));

                recipe->resultValue = recipeJson["ResultValue"].get<int32_t>();
                recipe->resultCount = recipeJson["ResultCount"].get<uint32_t>();
                auto remainsValueIt = recipeJson.find("RemainsValue");
                if(remainsValueIt != recipeJson.end())
                {
                    recipe->remainsValue = remainsValueIt->get<int32_t>();
                }
                auto remainsCountIt = recipeJson.find("RemainsCount");
                if(remainsCountIt != recipeJson.end())
                {
                    recipe->remainsCount = remainsCountIt->get<uint32_t>();
                }
                const nlohmann::json &ingredientsJson = recipeJson["Ingredients"];

                uint8_t key = (ingredientsJson.size() & 0xF) << 4;  // 行

                uint8_t columns = 0;
                for(int32_t index = 0; index < ingredientsJson.size(); ++index)
                {
                    std::string text = ingredientsJson[index].get<std::string>();
                    uint8_t textCount = text.length();
                    columns = MathUtils::Max<uint8_t>(columns, textCount);
                    for(int32_t textIndex = 0; textIndex < textCount; ++textIndex)
                    {
                        if(text[textIndex] != ' ')
                        {
                            std::string key(1, text[textIndex]);
                            recipe->ingredients[index * 3 + textIndex] = recipeJson[key][0].get<int32_t>();
                            recipe->ingredientsDataBit[index * 3 + textIndex] = recipeJson[key][1].get<int32_t>();
                        }
                    }
                }
                key |= (columns & 0xF);

                auto it = craftingRecipesMap.find(key);
                if(it == craftingRecipesMap.end())
                {
                    craftingRecipesMap[key] = { recipe };
                }
                else
                {
                    it->second.push_back(recipe);
                }
            }
        }
    }

    CraftingRecipe *CraftingRecipesManager::findCraftingRecipe(int32_t *ingredients)
    {
        CraftingRecipe *craftingRecipe = nullptr;
        int32_t array[9] = { 0 };
        uint8_t key = ArrangeRecipe(ingredients, array);
        auto it = craftingRecipesMap.find(key);
        if(it != craftingRecipesMap.end())
        {
            for(CraftingRecipe *recipe : it->second)
            {
                for(uint8_t index = 0; index < 9; ++index)
                {
                    if((array[index] & recipe->ingredientsDataBit[index]) != recipe->ingredients[index])
                    {
                        goto nextRecipe;
                    }
                }
                craftingRecipe = recipe;
                break;
            nextRecipe:;
            }
        }
        return craftingRecipe;
    }

    /**
     * @brief 排列合成表
     * 比如原先的合成表是       排列后将会是 
     *      [0,0,0]             [0,1,0]
     *      [0,0,1]             [1,0,0]
     *      [0,1,0]             [0,0,0]
    */
    uint8_t CraftingRecipesManager::ArrangeRecipe(int32_t *ingredients, int32_t *outIngredients)
    {
        uint8_t key = 0;
        uint8_t startX = UINT8_MAX;
        uint8_t startY = UINT8_MAX;
        uint8_t endX = 0;
        uint8_t endY = 0;
        for(uint8_t y = 0; y < 3; ++y)
        {
            for(uint8_t x = 0; x < 3; ++x)
            {
                if(ingredients[y * 3 + x] != 0)
                {
                    startX = MathUtils::Min<uint8_t>(x, startX);
                    startY = MathUtils::Min<uint8_t>(y, startY);
                    endX = MathUtils::Max(x, endX);
                    endY = MathUtils::Max(y, endY);
                }
            }
        }
        key =  (((endY - startY) & 0xF) + 1) << 4;
        key |= (((endX - startX) & 0xF) + 1);
        for(uint8_t y2 = startY, y = 0; y2 <= endY; ++y2, ++y)
        {
            for(uint8_t x2 = startX, x = 0; x2 <= endX; ++x2, ++x)
            {
                outIngredients[y * 3 + x] = ingredients[y2 * 3 + x2];
            }
        }
        return key;
    }

} // namespace PocketSurvival
